
import java.awt.Color;
import java.awt.Container;
import java.awt.Insets;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.PixelGrabber;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
 
public class FractalMaker {
    	
    	static JLabel enter1, enter2;
    	static MandelbrotCanvas1 theFrame;
		static Brush1 drawFrame;
    	static int count = 0;
    	
    	
	public static void addComponentsToPane(Container pane) {
        pane.setLayout(null);
     	
        //Setting up all buttons for the GUI.
        JButton refresh = new JButton("Refresh");
        JButton make = new JButton("Make");
        JButton change = new JButton("Change Color");
        JButton sizing = new JButton("Change Size");
        JButton moveRight = new JButton("Move Right");
        JButton moveLeft = new JButton("Move Left");
        JButton addPower = new JButton("Increase Power");
        JButton subPower = new JButton("Decrease Power");
        
        //Initializes the two main frame ares: Fractal(theFrame) Drawing(drawFrame).
        theFrame = new MandelbrotCanvas1();
		theFrame.setSize(900,900);
		theFrame.setVisible(true);
		
		drawFrame = new Brush1();
		drawFrame.setSize(250,250);
		drawFrame.setVisible(true);
        
        //Two labels for the two main areas.
        enter1 = new JLabel("Fractal:  ");
        enter2 = new JLabel("Drawing Area:  ");
        
        //Drop down boxes.
        final JComboBox color = new JComboBox();
        final JComboBox size = new JComboBox();
        
        //Adds buttons, labels, ComboBox, and frames to the GUI.
        pane.add(enter1);
        pane.add(enter2);
        pane.add(refresh);
        pane.add(make);
        pane.add(theFrame);
        pane.add(drawFrame);
        pane.add(change);
        pane.add(sizing);
        pane.add(color);
        pane.add(size);
        pane.add(moveLeft);
        pane.add(moveRight);
        pane.add(addPower);
        pane.add(subPower);
        
        //Colors and Sizes used by the drop down menus.
        final String[] colors = {"White","Red","Blue","Green","Yellow","Orange"};
        final int[] sizes = {10,5,7,13,15,17,20};
        
        //Puts colors into the color ComboBox
        for (int i = 0; i < 6; i++)
        {
        	color.addItem(colors[count++]);
           	change.addActionListener(new ActionListener()
           	{
        			public void actionPerformed(ActionEvent e)
        			{
        				if (count < colors.length)
        				{
        					color.addItem(colors[count++]);
        				}
        			}
        	}); 	
        }
        
        count = 0;
        
        //Puts sizes in the size ComboBox
        for (int i = 0; i < 7; i++)
        {
        	size.addItem(sizes[count++]);
        	sizing.addActionListener( new ActionListener()
        	{
        		public void actionPerformed(ActionEvent e)
        		{
        			if(count < sizes.length)
        			{
        				size.addItem(sizes[count++]);
        			}
        		}
        	});
        }
        
        //Dimension Setting for GUI sizing.
        Insets insets = pane.getInsets();
        Dimension refreshDim = refresh.getPreferredSize();
        Dimension enter1Dim = enter1.getPreferredSize();
        Dimension enter2Dim = enter2.getPreferredSize();
        Dimension changeDim = change.getPreferredSize();
        Dimension colorDim = color.getPreferredSize();
        
        //Setting the position of each button/label/comboBox/frame and such in the GUI.
        enter1.setBounds(0,0,enter1Dim.width, enter2Dim.height);
        theFrame.setBounds(0,enter1Dim.height,theFrame.getWidth(), theFrame.getHeight());
        
        enter2.setBounds(900,0,enter2Dim.width, enter2Dim.height);
        drawFrame.setBounds(900,enter1Dim.height,drawFrame.getWidth(), drawFrame.getHeight());
        
        make.setBounds(900+insets.left, 
        		insets.top + enter1Dim.height + drawFrame.getHeight(),
        		subPower.getPreferredSize().width, subPower.getPreferredSize().height);
        
        refresh.setBounds(900+insets.left+make.getWidth(), 
        		insets.top + drawFrame.getHeight()+enter2Dim.height,
        		addPower.getPreferredSize().width, addPower.getPreferredSize().height);
        
        change.setBounds(900+insets.left+make.getWidth(), 
				insets.top + drawFrame.getHeight()+enter2Dim.height + refreshDim.height,
				addPower.getPreferredSize().width, addPower.getPreferredSize().height);
        
        color.setBounds(900+insets.left, 
				insets.top + drawFrame.getHeight()+enter2Dim.height+refreshDim.height,
				addPower.getPreferredSize().width+5, addPower.getPreferredSize().height);
        
        sizing.setBounds(900+insets.left+make.getWidth(), 
				insets.top + drawFrame.getHeight()+enter2Dim.height + changeDim.height + refreshDim.height,
				addPower.getPreferredSize().width, addPower.getPreferredSize().height);
        
        size.setBounds(900+insets.left, 
				insets.top + drawFrame.getHeight()+enter2Dim.height+refreshDim.height+colorDim.height,
				addPower.getPreferredSize().width+5, addPower.getPreferredSize().height);
        
        moveLeft.setBounds(900+insets.left, 
				insets.top + drawFrame.getHeight()+enter2Dim.height+refreshDim.height+colorDim.height + sizing.getHeight(),
				subPower.getPreferredSize().width, subPower.getPreferredSize().height);
        
        moveRight.setBounds(900+insets.left+moveLeft.getWidth(), 
				insets.top + drawFrame.getHeight()+enter2Dim.height+refreshDim.height+colorDim.height + sizing.getHeight(),
				addPower.getPreferredSize().width, addPower.getPreferredSize().height);
        
        addPower.setBounds(900+insets.left+subPower.getPreferredSize().width, 
				insets.top + drawFrame.getHeight()+enter2Dim.height+refreshDim.height+colorDim.height + sizing.getHeight() + moveLeft.getHeight(),
				addPower.getPreferredSize().width, addPower.getPreferredSize().height);
        
        subPower.setBounds(900+insets.left, 
				insets.top + drawFrame.getHeight()+enter2Dim.height+refreshDim.height+colorDim.height + sizing.getHeight() + moveLeft.getHeight(),
				subPower.getPreferredSize().width, subPower.getPreferredSize().height);
        
        //ActionListener for the GUI.
        class event implements ActionListener 
        	{
        		public void actionPerformed(ActionEvent a) 
        		{
        			if(a.getActionCommand().equalsIgnoreCase("refresh"))
        			{
        			//Refreshes the entire GUI.
        			drawFrame.refresh();
        			theFrame.refresh();
        			theFrame.repaint();
        			}
        			else if(a.getActionCommand().equalsIgnoreCase("move left"))
        			{
        				//Scales the Fractal to the Left
        				theFrame.ux += .5;
        				theFrame.makecnSet();
           			 	theFrame.repaint();
        			}
        			else if(a.getActionCommand().equalsIgnoreCase("move right"))
        			{
        				//Scales the Fractal to the right.
        				theFrame.ux -= .5;
              			theFrame.makecnSet();     			 
              			theFrame.repaint();
        			}
        			else if(a.getActionCommand().equalsIgnoreCase("make"))
        			{
        			    //Initialized variables used to create the new fractal.     			
        				double[] fvars = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
        				double tred = 0, tgreen = 0, tblue = 0;
        				int r = 0, g = 0, b = 0;
        				PixelGrabber pg = new PixelGrabber(drawFrame.getBackbuffer(), 0, 0, -1, -1, false);
        				
        				//Gets pixels from the PixelGrabber.
        				try {
							pg.grabPixels();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
        				
        				//gets the pixels from the PixelGrabber and places them into the array.
        				int width = pg.getWidth();
        				int height = pg.getHeight();
        				int[] pixels = new int[width*height];
        				pixels = (int[])pg.getPixels();
        				int pix = 0;

        				//Alters the variables based on the pixel values.
        				for(int i = 0; i < width; i++)
        					for(int j = 0; j < height; j++) {
        						pix = (pixels[j*width+i] * -1) - 1;
        						
    							fvars[((i/25)+(j/25))%10] += pix * 1.0 / 16777216;
    							b = (pix)&0xFF;
    							g = (pix>>8)&0xFF;
    							r = (pix>>16)&0xFF;
    							tred += 255.0 - r;
    							tgreen += 255.0 - g;
    							tblue += 255.0 - b;
    						
        					}
        				        				
        				tred /= (250 * 250);
        				tgreen /= (250 * 250);
        				tblue /= (250 * 250);
        				
        			 //This section does coloring and the checks can be used to keep the coloring
        			 //from going to far or going negative.
    				theFrame.theRed = (int)(tred);
    				theFrame.theBlue = (int)(tblue);
    				theFrame.theGreen = (int)(tgreen);
        			 
    				//Checks threshold for coloring variables.
        			 if(theFrame.theBlue > 240)
        			 {
        				 theFrame.theBlue = 240;
        			 }
        			 else if(theFrame.theBlue < 0)
        			 {
        				 theFrame.theBlue = 0;
        			 }
        			 
        			 if(theFrame.theRed > 240)
        			 {
        				 theFrame.theRed = 240;
        			 }
        			 else if(theFrame.theRed < 0)
        			 {
        				 theFrame.theRed = 0;
        			 }
        			 
        			 if(theFrame.theGreen > 240)
        			 {
        				 theFrame.theGreen = 240;
        			 }
        			 else if(theFrame.theGreen < 0)
        			 {
        				 theFrame.theGreen = 0;
        			 }
        			 
        			 //Changes the initial point of the real and imaginary points for the z in the fractal formula
        			 theFrame.theStartX += .2 * (fvars[0]/6250);
        			 theFrame.theStartY -= .2 * (fvars[1]/6250);
        			
        			 
        			 if(fvars[2] > 3125)
        				 theFrame.makecnSet();
        			 if(fvars[3] < 1562.5)
        				 theFrame.thePower--;
        			 	if(theFrame.thePower < 1)
        			 	{
        			 		theFrame.thePower = 1;
        			 	}
        			 if(fvars[3] > 4687.5)
        				 theFrame.thePower++;
        			         			 
        			 theFrame.repaint();
        			}
        			else if(a.getActionCommand().equalsIgnoreCase("change color"))
        			{
        				//Changes the drawing color of the mouse.
        				drawFrame.changeColor(colors[color.getSelectedIndex()]);	
        			}
        			else if(a.getActionCommand().equalsIgnoreCase("change size"))
        			{
        				//Changes the size of the plotting area of the mouse.
        				drawFrame.changeSize(sizes[size.getSelectedIndex()]);
        			}
        			else if(a.getActionCommand().equalsIgnoreCase("increase power"))
        			{
        				//Increases the power of the fractal formula.
        				theFrame.thePower++;
        				theFrame.repaint();	
        			}
        			else if(a.getActionCommand().equalsIgnoreCase("decrease power"))
        			{
        				//Decreases the power of the fractal formula, but not below 1.
        				theFrame.thePower--;
        				if(theFrame.thePower < 1)
        				{
        					theFrame.thePower = 1;
        				}
        				theFrame.repaint();
        			}
        		}
        	}
        
        //Adds the actionListeners to each button.
        event a = new event();
        refresh.addActionListener(a);
        make.addActionListener(a);
        change.addActionListener(a);
        sizing.addActionListener(a);
        moveLeft.addActionListener(a);
        moveRight.addActionListener(a);
        addPower.addActionListener(a);
        subPower.addActionListener(a);
     }
	
	//Method which creates and Displays the GUI
	private static void createAndShowGUI() {
        //Create and set up the window.
        JFrame frame = new JFrame("FractalMaker");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 
        //Set up the content pane.
        addComponentsToPane(frame.getContentPane());
 
        //Size and display the window.
        Insets insets = frame.getInsets();
        frame.setSize(1200 + insets.left + insets.right,
                      1000 + insets.top + insets.bottom);
        frame.setVisible(true);
    }
 
    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
                drawFrame.init();
                theFrame.setBackground(Color.BLACK);
                theFrame.draw();
            }
        });
    }
}